﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using конфигуратор;

namespace Wpfконфигуратор.Визуализаторы
{
    public class ПолеВизуализатор : INotifyPropertyChanged    ,IComparable<ПолеВизуализатор>     ,IПеременная
    {
        public  ДинамикОбъект ДинОбъект;
        public FieldInfo F { get; set;}

        public int НомерНаследника { get; set; }
        public ОписаниеТипа ИмяТипаОпределившегоПоле { get { return new ОписаниеТипа( F.DeclaringType); } }
        public ОписаниеТипа ТипПеременной { get { return new ОписаниеТипа( F.FieldType); } }
        public string ИмяПоля { get { return F.Name; } }

        public object Значение
        {
            get
            {
                    if ( ДинОбъект.Объект ==null)   return null;  
                    return F.GetValue( ДинОбъект.Объект );
            }
            set
            {
                try
                {
                    F.SetValue( ДинОбъект.Объект, value );
                    Обновить();  
                    // поля влияют на значения свойств, значит нужно обновить все свойства 
                    ДинОбъект.Обновить("Свойства");
                }
                catch   { }
            }
        }

        public void Удалить ()
        {
            Значение=null;
            Визуализатор = null;
            ОбновитьСвойство("ВизуализаторЗначения");
        }

        //private DelegateCommand<object> DC;  
        public ПеременнаяВизуализатор ДиалогСоздания {get {return new ПеременнаяВизуализатор(){Переменная = this};}}
     
         // ищет в некотрой базе класс или DataTemplate
        public ВизуализаторОснова Визуализатор;
        public ВизуализаторОснова ВизуализаторЗначения
        {
            get
            {
                return Визуализатор ?? (Визуализатор= ВыборВизуализатора.Выбрать(this));
            }
            set { Визуализатор=value; }
        }

        private string _атрибутыДоступа;
        public string АтрибутыДоступа
        {
            get
            {
                if ( _атрибутыДоступа != null ) return _атрибутыДоступа;
                if ( F.IsPrivate ) return _атрибутыДоступа="private";
                if ( F.IsPublic ) return _атрибутыДоступа = "public";
                if ( F.IsFamilyOrAssembly ) return _атрибутыДоступа = "protected internal";
                if ( F.IsAssembly ) return _атрибутыДоступа = "internal";
                if ( F.IsFamily ) return _атрибутыДоступа = "protected";
                return "";
              }
        }
        public string АтрибутФиксации
        { get
        {
            if ( F.IsLiteral ) return "const";
            if ( F.IsInitOnly ) return "readonly";
            return null;
        }}

        private string _синтаксис;
        public string Синтаксис
        {
            get
            {
                if ( _синтаксис != null ) return _синтаксис;
                return _синтаксис= F.DeclaringType.ИмяТипа() + "\r\n"
                    +АтрибутыИнфо.СинтаксисАтрибутов(F.GetCustomAttributesData())+
                    АтрибутыДоступа + " " + (АтрибутФиксации==null ? "": АтрибутФиксации+" ")  + F.FieldType.ИмяТипа() + " " + F.Name;
            }
        }
         public override string ToString ()
        {
            return base.ToString()+" "+ F.Name + " : " + Значение;
        }       

        public event PropertyChangedEventHandler PropertyChanged;
         public void ОбновитьСвойство(string имяСвойства)
        {
            if ( PropertyChanged != null )
             PropertyChanged( this, new PropertyChangedEventArgs( имяСвойства ) );
          }

        public void Обновить()
        {
            if ( PropertyChanged != null )
            { PropertyChanged( this, new PropertyChangedEventArgs( "" ) );
            Визуализатор.ОбновитьСвойство( "" );
            //визуализатор меняется  если меняется тип объекта или вручную меняется визуализатор 
            //PropertyChanged( this, new PropertyChangedEventArgs( "ВизуализаторЗначения" ) );
            }
        }
          public static List<ПолеВизуализатор> ДатьСписокПолейОбъекта(ДинамикОбъект динОбъект  )
        {
            return ДатьСписокПолей(динОбъект, BindingFlags.Instance);
        }
        public static List<ПолеВизуализатор> ДатьСписокПолейТипа ( ДинамикОбъект динОбъект )
        {
            return ДатьСписокПолей( динОбъект, BindingFlags.Static );
        }

         private static List<ПолеВизуализатор> ДатьСписокПолей ( ДинамикОбъект динОбъект , BindingFlags bindingFlags )
        {
           
            if ( динОбъект == null || динОбъект.Тип ==null ) return null;
             var списокПолей = new List<ПолеВизуализатор>();

             var предки = динОбъект.ОписаниеТипа.Предки.ToList();
             предки.Insert( 0, динОбъект.Тип );

             for ( int номер = 0; номер < предки.Count; номер++ )
             {
                 var массив = предки[номер].GetFields( bindingFlags | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly );
                 foreach ( var поле in массив )
                 {
                     списокПолей.Add( new ПолеВизуализатор() { ДинОбъект = динОбъект, F = поле, НомерНаследника = номер } );
                 }
             }
             списокПолей.Sort();
            return списокПолей;
        }


        public int CompareTo ( ПолеВизуализатор other )
        {
            var рез = АтрибутыДоступа.CompareTo( other.АтрибутыДоступа );
            if ( рез == 0 )
                return F.Name.CompareTo( other.F.Name );
            return -рез;
        }
      
    }
}
